﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.IO;
using System.Web;
using System.Xml;
using System.Threading;
using System.Data.OleDb;
using System.Text.RegularExpressions;
using System.Net;

namespace AliCMS.CollectModule.Bll
{
    public partial class Rule : DbObjectBase, IRule
    {
        public class Result : DbObjectBase, CollectModule.Rule.IResult
        {
            public Result(int instanceID, string lang, bool checkRight, string database)
                : base(instanceID, lang, checkRight, database)
            {
            }

            public override object ExecuteService(HttpContext context)
            {
                object result = null;

                string operation = context.Request.QueryString["Operation"];
                if (operation == "Delete")
                {
                    int ruleID = Convert.ToInt32(context.Request.QueryString["RuleID"]);
                    string id = context.Request.QueryString["ID"];

                    string[] ids = id.Split('|');
                    for (int i = 0; i < ids.Length; i++)
                    {
                        if (String.IsNullOrEmpty(ids[i]))
                            continue;

                        Delete(ruleID, Convert.ToInt32(ids[i]));
                    }
                }
                else if (operation == "List")
                {
                    string value = null;

                    int page = -1;
                    value = context.Request.QueryString["Page"];
                    if (value != null) page = Convert.ToInt32(value);

                    int pageSize = -1;
                    value = context.Request.QueryString["PageSize"];
                    if (value != null) pageSize = Convert.ToInt32(value);

                    string condition = context.Request.QueryString["Condition"];
                    string sort = context.Request.QueryString["Sort"];

                    result = List(page, pageSize, condition, sort);
                }
                else if (operation == "Replace")
                {
                    int ruleID = Convert.ToInt32(context.Request.QueryString["RuleID"]);
                    string property = context.Request.Form["Property"];
                    string from = context.Request.Form["From"];
                    string to = context.Request.Form["To"];
                    Replace(ruleID, property, from, to);
                }
                else
                {
                    throw new Exception("lang_header_param");
                }

                return result;
            }

            public void Delete(int ruleID, int id)
            {
                if (CheckRight)
                {
                    ValidateRight("Delete", Guid.Empty);
                }

                #region 获取配置
                XmlDocument config = null;
                using (Rule bll = new Rule(InstanceID, Lang, false, null))
                {
                    Dictionary<string, object> rule = bll.Get(ruleID);
                    if (rule[Alias.Rule.Config].ToString() != String.Empty)
                    {
                        config = new XmlDocument();
                        config.LoadXml(rule[Alias.Rule.Config].ToString());
                    }
                }

                if (config == null)
                    return;

                string tableName = config.DocumentElement.Attributes["Name"].Value;
                #endregion

                #region 获取栏目配置
                string connectionString = null;
                using (IInstanceConfig configBll = (IInstanceConfig)Manager.CreateObject("InstanceConfig", InstanceID, Lang, false))
                {
                    Dictionary<string, string> instanceConfig = configBll.GetBasicSettings();
                    connectionString = instanceConfig[Alias.InstanceConfig.ConnectionString];
                    connectionString = connectionString.Replace("{#InstancePath#}", Manager.MapPath(Manager.GetDataPath(InstanceID, null)));
                    connectionString = connectionString.Replace("{#WebPath#}", Manager.MapPath(Manager.GetWebPath()));
                    connectionString = connectionString.Replace("{#DataPath#}", Manager.MapPath(Manager.GetDataPath(null, null)));
                }

                if (String.IsNullOrEmpty(connectionString))
                    return;

                string db = null;
                string[] parts = connectionString.Split(';');
                foreach (string part in parts)
                {
                    string[] pair = part.Split('=');
                    if (pair[0] == "Data Source")
                    {
                        db = pair[1];
                        break;
                    }
                }
                if (db == null || !File.Exists(db))
                    return;
                #endregion

                #region 打开数据库
                OleDbConnection connection = new OleDbConnection(connectionString);
                connection.Open();
                OleDbCommand command = new OleDbCommand();
                command.Connection = connection;
                #endregion

                #region 执行删除
                command.CommandText = "DELETE FROM [" + tableName + "] WHERE [ID]=" + id;
                command.ExecuteNonQuery();
                #endregion

                #region 关闭数据库
                connection.Close();
                #endregion
            }
            public DataTable List(int page, int pageSize, string condition, string sort)
            {
                if (CheckRight)
                {
                    ValidateRight("List", Guid.Empty);
                }

                DataTable result = new DataTable();
                result.Columns.Add(Alias.Rule.Result.ID, typeof(int));
                result.Columns.Add(Alias.Rule.Result.RuleID, typeof(Guid));
                result.Columns.Add(Alias.Rule.Result.CreateTime, typeof(DateTime));

                #region 获取配置
                Match match = Regex.Match(condition, @"(?<=(^|\s|\())\[RuleID\]\s?=\s?((?<InnerID>\d+)|(?<Guid>(\{|'|'\{)?[a-fA-F0-9]{8}(-?[a-fA-F0-9]{4}){3}-?[a-fA-F0-9]{12}(\}|'|\}')?))(?=(\s|\)|$))", RegexOptions.Compiled | RegexOptions.IgnoreCase);
                if (!match.Success)
                    return result;

                object id = null;
                if (match.Groups["InnerID"].Success)
                    id = Convert.ToInt32(match.Groups["InnerID"].Value);
                else
                    id = new Guid(match.Groups["Guid"].Value);

                XmlDocument config = null;
                using (Rule bll = new Rule(InstanceID, Lang, false, null))
                {
                    Dictionary<string, object> rule = bll.Get(id);
                    if (rule[Alias.Rule.Config].ToString() != String.Empty)
                    {
                        config = new XmlDocument();
                        config.LoadXml(rule[Alias.Rule.Config].ToString());
                    }
                }

                if (config == null)
                    return result;

                string tableName = config.DocumentElement.Attributes["Name"].Value;

                XmlNodeList fieldNodes = config.DocumentElement.SelectNodes("Fields/Field");
                foreach (XmlNode fieldNode in fieldNodes)
                {
                    if (fieldNode.Attributes["Name"] == null || fieldNode.Attributes["IsDisplay"] == null || fieldNode.Attributes["IsDisplay"].Value != "1")
                        continue;

                    Type type = typeof(string);
                    if (fieldNode.Attributes["DataType"] != null)
                    {
                        if (fieldNode.Attributes["DataType"].Value == "Number")
                            type = typeof(int);
                        else if (fieldNode.Attributes["DataType"].Value == "Float")
                            type = typeof(decimal);
                        else if (fieldNode.Attributes["DataType"].Value == "Guid")
                            type = typeof(Guid);
                        else
                            type = typeof(string);
                    }

                    result.Columns.Add(fieldNode.Attributes["Name"].Value, type);
                }
                #endregion

                #region 条件
                StringBuilder where = new StringBuilder(" WHERE " + condition);
                #endregion

                #region 排序
                if (!String.IsNullOrEmpty(sort))
                    sort = " ORDER BY " + sort;
                else
                    sort = " ORDER BY [ID] DESC";
                #endregion

                #region 获取栏目配置
                string connectionString = null;
                using (IInstanceConfig configBll = (IInstanceConfig)Manager.CreateObject("InstanceConfig", InstanceID, Lang, false))
                {
                    Dictionary<string, string> instanceConfig = configBll.GetBasicSettings();
                    connectionString = instanceConfig[Alias.InstanceConfig.ConnectionString];
                    connectionString = connectionString.Replace("{#InstancePath#}", Manager.MapPath(Manager.GetDataPath(InstanceID, null)));
                    connectionString = connectionString.Replace("{#WebPath#}", Manager.MapPath(Manager.GetWebPath()));
                    connectionString = connectionString.Replace("{#DataPath#}", Manager.MapPath(Manager.GetDataPath(null, null)));
                }

                if (String.IsNullOrEmpty(connectionString))
                    return result;

                string db = null;
                string[] parts = connectionString.Split(';');
                foreach (string part in parts)
                {
                    string[] pair = part.Split('=');
                    if (pair[0] == "Data Source")
                    {
                        db = pair[1];
                        break;
                    }
                }
                if (db == null || !File.Exists(db))
                    return result;
                #endregion

                #region 打开数据库
                OleDbConnection connection = new OleDbConnection(connectionString);
                connection.Open();
                OleDbCommand command = new OleDbCommand();
                command.Connection = connection;
                #endregion

                #region 检查数据表是否存在，如果不存在创建一个
                DataTable tables = connection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new object[] { null, null, tableName, "TABLE" });
                if (tables.Rows.Count == 0)
                {
                    string s = "CREATE TABLE [" + tableName + "]([ID] int identity(1,1) UNIQUE PRIMARY KEY,[RuleID] uniqueidentifier,[CreateTime] datetime default now()";
                    foreach (XmlNode fieldNode in fieldNodes)
                    {
                        if (fieldNode.Attributes["Name"] == null)
                            continue;

                        string dataType = " nvarchar(255)";
                        if (fieldNode.Attributes["DataType"] != null)
                        {
                            if (fieldNode.Attributes["DataType"].Value == "Number")
                                dataType = " int";
                            else if (fieldNode.Attributes["DataType"].Value == "Float")
                                dataType = " decimal(10,3)";
                            else if (fieldNode.Attributes["DataType"].Value == "Guid")
                                dataType = " uniqueidentifier";
                            else if (fieldNode.Attributes["DataType"].Value == "Memo")
                                dataType = " ntext";
                            else
                                dataType = " nvarchar(255)";
                        }
                        s += ",[" + fieldNode.Attributes["Name"].Value + "]" + dataType;
                    }
                    s += ")";

                    command.CommandText = s;
                    command.ExecuteNonQuery();
                }
                #endregion

                #region 检查字段是否存在，不存在，则创建
                DataTable fieldTable = connection.GetOleDbSchemaTable(OleDbSchemaGuid.Columns, new object[] { null, null, tableName, null });
                foreach (XmlNode fieldNode in fieldNodes)
                {
                    bool exist = false;
                    foreach (DataRow fieldRow in fieldTable.Rows)
                    {
                        if (fieldNode.Attributes["Name"].Value == fieldRow["COLUMN_NAME"].ToString())
                        {
                            exist = true;
                            break;
                        }
                    }

                    if (exist)
                        continue;

                    string dataType = " nvarchar(255)";
                    if (fieldNode.Attributes["DataType"] != null)
                    {
                        if (fieldNode.Attributes["DataType"].Value == "Number")
                            dataType = " int";
                        else if (fieldNode.Attributes["DataType"].Value == "Float")
                            dataType = " decimal(10,3)";
                        else if (fieldNode.Attributes["DataType"].Value == "Guid")
                            dataType = " uniqueidentifier";
                        else if (fieldNode.Attributes["DataType"].Value == "Memo")
                            dataType = " ntext";
                        else
                            dataType = " nvarchar(255)";
                    }

                    command.CommandText = "ALTER TABLE [" + tableName + "] ADD [" + fieldNode.Attributes["Name"].Value + "]" + dataType;
                    command.ExecuteNonQuery();
                }
                #endregion

                #region 构造SQL语句
                StringBuilder sql = new StringBuilder("SELECT");
                if (page > 0 && pageSize > 0)
                    sql.Append(" TOP " + (page * pageSize));
                sql.Append(" [ID]");
                sql.Append(",[RuleID]");
                sql.Append(",[CreateTime]");

                foreach (XmlNode fieldNode in fieldNodes)
                {
                    if (fieldNode.Attributes["Name"] == null || fieldNode.Attributes["IsDisplay"] == null || fieldNode.Attributes["IsDisplay"].Value != "1")
                        continue;

                    sql.Append(",[" + fieldNode.Attributes["Name"].Value + "]");
                }

                sql.Append(" FROM [" + tableName + "]");
                sql.Append(where + sort);
                command.CommandText = sql.ToString();
                #endregion

                #region 执行SQL语句并获取记录
                int curIndex = 0, rowIndex = 0;
                int startIndex = (page - 1) * pageSize;
                OleDbDataReader reader = command.ExecuteReader();
                while (reader.Read())
                {
                    if (pageSize != -1)
                    {
                        if (curIndex < startIndex)
                        {
                            curIndex++;
                            continue;
                        }

                        if (rowIndex == pageSize)
                            break;
                    }

                    DataRow row = result.NewRow();
                    int i = 0;
                    row[Alias.Rule.Result.ID] = reader[i++];
                    row[Alias.Rule.Result.RuleID] = reader[i++];
                    row[Alias.Rule.Result.CreateTime] = reader[i++];
                    
                    foreach (XmlNode fieldNode in fieldNodes)
                    {
                        if (fieldNode.Attributes["Name"] == null || fieldNode.Attributes["IsDisplay"] == null || fieldNode.Attributes["IsDisplay"].Value != "1")
                            continue;

                        row[fieldNode.Attributes["Name"].Value] = reader[i++];
                    }

                    result.Rows.Add(row);

                    rowIndex++;
                }
                reader.Close();
                #endregion

                #region 关闭数据库
                connection.Close();
                #endregion

                return result;
            }
            public int GetRecordCount(string condition)
            {
                #region 获取配置
                Match match = Regex.Match(condition, @"(?<=(^|\s|\())\[RuleID\]\s?=\s?((?<InnerID>\d+)|(?<Guid>(\{|'|'\{)?[a-fA-F0-9]{8}(-?[a-fA-F0-9]{4}){3}-?[a-fA-F0-9]{12}(\}|'|\}')?))(?=(\s|\)|$))", RegexOptions.Compiled | RegexOptions.IgnoreCase);
                if (!match.Success)
                    return 0;

                object id = null;
                if (match.Groups["InnerID"].Success)
                    id = Convert.ToInt32(match.Groups["InnerID"].Value);
                else
                    id = new Guid(match.Groups["Guid"].Value);

                XmlDocument config = null;
                using (Rule bll = new Rule(InstanceID, Lang, false, null))
                {
                    Dictionary<string, object> rule = bll.Get(id);
                    if (rule[Alias.Rule.Config].ToString() != String.Empty)
                    {
                        config = new XmlDocument();
                        config.LoadXml(rule[Alias.Rule.Config].ToString());
                    }
                }

                if (config == null)
                    return 0;

                string tableName = config.DocumentElement.Attributes["Name"].Value;
                #endregion

                #region 条件
                StringBuilder where = new StringBuilder(" WHERE " + condition);
                #endregion

                #region 获取栏目配置
                string connectionString = null;
                using (IInstanceConfig configBll = (IInstanceConfig)Manager.CreateObject("InstanceConfig", InstanceID, Lang, false))
                {
                    Dictionary<string, string> instanceConfig = configBll.GetBasicSettings();
                    connectionString = instanceConfig[Alias.InstanceConfig.ConnectionString];
                    connectionString = connectionString.Replace("{#InstancePath#}", Manager.MapPath(Manager.GetDataPath(InstanceID, null)));
                    connectionString = connectionString.Replace("{#WebPath#}", Manager.MapPath(Manager.GetWebPath()));
                    connectionString = connectionString.Replace("{#DataPath#}", Manager.MapPath(Manager.GetDataPath(null, null)));
                }

                if (String.IsNullOrEmpty(connectionString))
                    return 0;

                string db = null;
                string[] parts = connectionString.Split(';');
                foreach (string part in parts)
                {
                    string[] pair = part.Split('=');
                    if (pair[0] == "Data Source")
                    {
                        db = pair[1];
                        break;
                    }
                }
                if (db == null || !File.Exists(db))
                    return 0;
                #endregion

                #region 打开数据库
                OleDbConnection connection = new OleDbConnection(connectionString);
                connection.Open();
                OleDbCommand command = new OleDbCommand();
                command.Connection = connection;
                #endregion

                command.CommandText = "SELECT COUNT(*) FROM " + tableName + where;
                int result = Convert.ToInt32(command.ExecuteScalar());

                #region 关闭数据库
                connection.Close();
                #endregion

                return result;
            }

            public void Replace(int ruleID, string property, string from, string to)
            {
                if (CheckRight)
                {
                    ValidateRight("Replace", Guid.Empty);
                }

                #region 获取配置
                Dictionary<string, object> rule = null;
                XmlDocument config = null;
                using (Rule bll = new Rule(InstanceID, Lang, false, null))
                {
                    rule = bll.Get(ruleID);
                    if (rule[Alias.Rule.Config].ToString() != String.Empty)
                    {
                        config = new XmlDocument();
                        config.LoadXml(rule[Alias.Rule.Config].ToString());
                    }
                }

                if (config == null)
                    return;

                string tableName = config.DocumentElement.Attributes["Name"].Value;
                #endregion

                #region 获取栏目配置
                string connectionString = null;
                using (IInstanceConfig configBll = (IInstanceConfig)Manager.CreateObject("InstanceConfig", InstanceID, Lang, false))
                {
                    Dictionary<string, string> instanceConfig = configBll.GetBasicSettings();
                    connectionString = instanceConfig[Alias.InstanceConfig.ConnectionString];
                    connectionString = connectionString.Replace("{#InstancePath#}", Manager.MapPath(Manager.GetDataPath(InstanceID, null)));
                    connectionString = connectionString.Replace("{#WebPath#}", Manager.MapPath(Manager.GetWebPath()));
                    connectionString = connectionString.Replace("{#DataPath#}", Manager.MapPath(Manager.GetDataPath(null, null)));
                }

                if (String.IsNullOrEmpty(connectionString))
                    return;

                string db = null;
                string[] parts = connectionString.Split(';');
                foreach (string part in parts)
                {
                    string[] pair = part.Split('=');
                    if (pair[0] == "Data Source")
                    {
                        db = pair[1];
                        break;
                    }
                }
                if (db == null || !File.Exists(db))
                    return;
                #endregion

                #region 打开数据库
                OleDbConnection connection = new OleDbConnection(connectionString);
                connection.Open();
                OleDbCommand command = new OleDbCommand();
                command.Connection = connection;
                #endregion

                #region 替换
                command.Parameters.Clear();
                command.Parameters.Add("@RuleID", OleDbType.Guid).Value = rule[Alias.Rule.ID];
                command.Parameters.Add("@" + property, OleDbType.VarWChar).Value = from;//这里直接用了VarWChar类型，是因为sqlserver2005上下面的执行代码出错

                OleDbDataAdapter adapter = new OleDbDataAdapter();
                adapter.SelectCommand = command;

                DataTable result = new DataTable();
                command.CommandText = "SELECT [" + property + "],[ID] FROM [" + tableName + "] WHERE [RuleID]=? AND [" + property + "] LIKE '%' + ? + '%'";
                adapter.Fill(result);

                command.Parameters.RemoveAt(0);//移除RuleID

                command.Parameters.Add("@ID", OleDbType.Integer);
                foreach (DataRow row in result.Rows)
                {
                    command.Parameters[0].Value = row[0].ToString().Replace(from, to);
                    command.Parameters[1].Value = row[1];
                    command.CommandText = "UPDATE [" + tableName + "] SET [" + property + "]=? WHERE [ID]=?";
                    command.ExecuteNonQuery();
                }
                #endregion

                #region 关闭数据库
                connection.Close();
                #endregion
            }
        }
    }
}
